/*
 * ClusterClientApp2.java
 *
 * Created on March 22, 2002, 12:54 PM
 */

package org.coinor.opents.net;

import java.io.*;
import java.net.*;
import java.rmi.*;
import java.rmi.server.*;

/**
 *
 * @author  Administrator
 */
public class ClusterClientApp 
extends javax.swing.JFrame 
implements ClusterConstants
{

    /** Creates new form ClusterClientApp2 */
    public ClusterClientApp() {
        initComponents();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    private void initComponents()//GEN-BEGIN:initComponents
    {
        clusterClientController = new org.coinor.opents.net.ClusterClientController();
        lblNote1 = new javax.swing.JLabel();
        lblNote2 = new javax.swing.JLabel();
        lblNote3 = new javax.swing.JLabel();
        lblINetAddr = new javax.swing.JLabel();
        lblNote4 = new javax.swing.JLabel();
        lblNumClusters = new javax.swing.JLabel();
        
        
        getContentPane().setLayout(new java.awt.GridLayout(6, 0));
        
        setTitle(java.util.ResourceBundle.getBundle("org/coinor/opents/net/strings").getString("clusterclientapp.frame.title"));
        addWindowListener(new java.awt.event.WindowAdapter()
        {
            public void windowClosing(java.awt.event.WindowEvent evt)
            {
                exitForm(evt);
            }
        });
        
        lblNote1.setFont(new java.awt.Font("Dialog", 0, 12));
        lblNote1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        lblNote1.setText(java.util.ResourceBundle.getBundle("org/coinor/opents/net/strings").getString("client.note.1"));
        getContentPane().add(lblNote1);
        
        lblNote2.setFont(new java.awt.Font("Dialog", 0, 12));
        lblNote2.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        lblNote2.setText(java.util.ResourceBundle.getBundle("org/coinor/opents/net/strings").getString("client.note.2"));
        getContentPane().add(lblNote2);
        
        lblNote3.setFont(new java.awt.Font("Dialog", 0, 12));
        lblNote3.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        lblNote3.setText(java.util.ResourceBundle.getBundle("org/coinor/opents/net/strings").getString("client.note.3"));
        getContentPane().add(lblNote3);
        
        lblINetAddr.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        try
        { lblINetAddr.setText( java.net.InetAddress.getLocalHost().toString() ); }catch(Exception e )
        {}
        getContentPane().add(lblINetAddr);
        
        lblNote4.setFont(new java.awt.Font("Dialog", 0, 12));
        lblNote4.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        lblNote4.setText(java.util.ResourceBundle.getBundle("org/coinor/opents/net/strings").getString("client.note.4"));
        getContentPane().add(lblNote4);
        
        lblNumClusters.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        lblNumClusters.setText("0");
        getContentPane().add(lblNumClusters);
        
        pack();
        java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        setSize(new java.awt.Dimension(350, 140));
        setLocation((screenSize.width-350)/2,(screenSize.height-140)/2);
    }//GEN-END:initComponents

    /** Exit the Application */
    private void exitForm(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_exitForm
        System.exit(0);
    }//GEN-LAST:event_exitForm

    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) 
    {
        initSecurity();
        
        ClusterClientApp cca = new ClusterClientApp();
        cca.show();
        try{
            cca.startClientTabuSearchFactoryServices(); 
            cca.startDatagramServices();
        }   // end try
        catch( Exception e ){
            e.printStackTrace();
        }   // end catch
    }


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private org.coinor.opents.net.ClusterClientController clusterClientController;
    private javax.swing.JLabel lblNote1;
    private javax.swing.JLabel lblNote2;
    private javax.swing.JLabel lblNote3;
    private javax.swing.JLabel lblINetAddr;
    private javax.swing.JLabel lblNote4;
    private javax.swing.JLabel lblNumClusters;
    // End of variables declaration//GEN-END:variables

    
    
    
    private MulticastSocket dgSocket;
    private InetAddress multicastGroup;
    private int datagramPort = 5815;
    private Thread shutdownHook;
    
    
    public static void main2 (String args[]) 
    {
        initSecurity();
        
        ClusterClientApp cca = new ClusterClientApp();
        try{
            cca.startClientTabuSearchFactoryServices(); 
            cca.startDatagramServices();
        }   // end try
        catch( Exception e ){
            e.printStackTrace();
        }   // end catch
    }
    
    
    
    public static void initSecurity()
    {
        
        java.net.URL codebase = null;
        try{
            codebase = new java.net.URL( System.getProperty("java.rmi.server.codebase") );
        }   // end try
        catch( java.net.MalformedURLException e ){
            //e.printStackTrace();
            // No surprise if no codebase was set from command line
        }   // end catch
        
        if( System.getProperty("java.rmi.server.codebase") == null ){
            try{
                ClassLoader c = ClassLoader.getSystemClassLoader();
                codebase = c.getResource("org/coinor/opents/net/ClusterClientApp.class");
                String newUrl = codebase.toString().substring(0,codebase.toString().lastIndexOf("org/coinor/opents/net/ClusterClientApp.class") );
                codebase = new java.net.URL( newUrl );
                
                System.setProperty("java.rmi.server.codebase", codebase.toString());
            }   // end try
            catch( Exception e ){
                e.printStackTrace();
            }   // end catch
        }   // end if: code base
        
        
        if( System.getProperty("java.security.policy") == null ){
            try{
                System.setProperty("java.security.policy", new java.net.URL( codebase, "policy.all" ).toString() );
            }   // end try
            catch( Exception e ){
                e.printStackTrace();
            }   // end catch
        }   // end if: security policy
        
        
        if (System.getSecurityManager() == null){
            System.setSecurityManager(new RMISecurityManager());
        }   // end if: no security manager
        else 
            System.out.println("Security Manager already installed" );
    }   // end initSecurity
    
    

    
    
    public synchronized void startClientTabuSearchFactoryServices() throws java.io.IOException
    {
        String name = "ClientTabuSearchFactory";
        
        System.out.print("Instantiating...");
        ClientTabuSearchFactory clientFactory = new ClientTabuSearchFactoryImpl(this);
        System.out.println("Done.");
        System.out.print( "Rebinding...");
        Naming.rebind(name, clientFactory);
        System.out.println("Done.");
        System.out.println("ClientTabuSearchFactory bound");
    }   // end startClientTabuSearchFactoryServices
    
    
    public synchronized void stopClientTabuSearchFactoryServices()
    {
        
    }   // end stopClientTabuSearchFactoryServices
    
    
    
    
    
/* ********  D A T A G R A M   M E T H O D S  ******** */    
    
    
    
    public synchronized void startDatagramServices() throws java.io.IOException
    {
        if( dgSocket != null )
            return;
        
        multicastGroup = InetAddress.getByName("230.0.0.1");
        
        dgSocket = new MulticastSocket( getDatagramPort() );
        dgSocket.joinGroup( multicastGroup );
        
        dgSocket.send( new DatagramPacket( new byte[]{ I_AM_A_CLIENT }, 1, multicastGroup, getDatagramPort() ) );

        final DatagramSocket DgSocket = dgSocket;
        Thread t = new Thread( new Runnable(){
            public void run(){
                byte[] buffer = new byte[32];
                DatagramPacket dg = new DatagramPacket( buffer, buffer.length );
                try{
                    while( true ){
                        DgSocket.receive( dg );
                        handleIncomingDatagram( dgSocket, dg );
                    }   // end while
                }   // end try
                catch( IOException e ){
                    e.printStackTrace();
                }   // end catch
                finally{        
                    stopDatagramServices();
                }   // end finally
            }   // end run
        });
        t.start();
        
        shutdownHook = new Thread( new Runnable(){
            public void run(){
                System.out.println( "Shutdown hook started." );
                try{
                    DgSocket.send( new DatagramPacket( new byte[]{ I_AM_A_CLIENT_LEAVING }, 1, multicastGroup, getDatagramPort() ) );
                }   // end try
                catch( Exception e){
                    e.printStackTrace();
                }
            }   // end run
        });
        Runtime.getRuntime().addShutdownHook( shutdownHook );
    }   // end startDatagramServices
    
    
    public synchronized void stopDatagramServices()
    {
        if( dgSocket == null )
            return;
        
        try{
            dgSocket.send( new DatagramPacket( new byte[]{ I_AM_A_CLIENT_LEAVING }, 1, multicastGroup, getDatagramPort() ) );
        }   // end try
        catch( IOException e ){
            e.printStackTrace();
        }   // end catch
        
        try{    
            dgSocket.leaveGroup( multicastGroup );
        }   // end try
        catch( IOException e ){
            e.printStackTrace(); 
        }   // end catch
        dgSocket.close();
        this.dgSocket = null;
        
        if( shutdownHook != null )
            Runtime.getRuntime().removeShutdownHook( shutdownHook );
    }   // end stopDatagramServices
    
    
    
    private void handleIncomingDatagram( DatagramSocket socket, DatagramPacket packet ) throws java.io.IOException
    {
        int off    = packet.getOffset();
        int len    = packet.getLength();
        byte[] dat = packet.getData();   
        
        if( len == 0 )
            return;
        
        byte firstByte = dat[off];
        
        switch( firstByte ){
            case REQUEST_CLIENT_RESPONSE:
                System.out.println( "Got request for client response." );
                dat[0] = I_AM_A_CLIENT;
                System.out.println( "  Request came from " + packet.getAddress() );
                socket.send( new DatagramPacket( dat, 1, multicastGroup, getDatagramPort() ) );
                break;
            default:
                System.out.println( "Unhandled request: " + firstByte );
                break;
        }   // end switch
    }   // end handleIncomingDatagram
    
    
    public int getDatagramPort()
    {
        return datagramPort;
    }   // end getDatagramPort
    
    
/* ********  C A L L   B A C K   M E T H O D S   F O R   F A C T O R Y  ******** */
    // Please, let's not keep this horrible callback style around forever.
    
    
    public void clientTabuSearchCreated( ClientTabuSearchFactory factory )
    {
        String s = lblNumClusters.getText();
        Integer I = new Integer(0);
        try{ I = new Integer(s); }
        catch( Exception e ){}
        final Integer NewI = new Integer( I.intValue() + 1 );
        final javax.swing.JLabel Lbl = lblNumClusters;
        javax.swing.SwingUtilities.invokeLater( new Runnable(){
            public void run(){
                Lbl.setText( NewI.toString() );
            }   // end run
        }); // end invokeLater
    }   // end clientTabuSearchCreated
    
    
    
    
}
